package com.liuyjy.base.redis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.liuyjy.base.redis.lock.RedissonLockAspect;
import com.liuyjy.base.redis.util.RedisCache;
import com.liuyjy.base.redis.util.RedisCacheImpl;
import com.liuyjy.base.redis.util.RedisLockUtil;
import com.liuyjy.base.redis.util.RedissonLockUtil;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.TransportMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author: liuyjy
 * @Description: 配置信息
 * @date: 2022/2/10 14:05
 */
@Configuration
public class RedisConfig {


    @Autowired
    private Environment env;

    /**
     * https://www.cnblogs.com/javalinux/p/14265383.html
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "common.setting.redisson.host")
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.setTransportMode(TransportMode.NIO);
        config.useSingleServer()
                //可以用"rediss://"来启用SSL连接
                .setAddress("redis://" + env.getProperty("common.setting.redisson.host"))
                .setPassword(env.getProperty("common.setting.redisson.password"));
        return Redisson.create(config);
    }

    @Bean
    @ConditionalOnProperty(name = "common.setting.redisson.host")
    @ConditionalOnMissingBean
    public RedissonLockAspect redissonLockLockAspect() {
        return new RedissonLockAspect();
    }

    @Bean
    @ConditionalOnMissingBean
    public RedisCache redisCache() {
        return new RedisCacheImpl();
    }

    /**
     * 分布式锁处理
     */
    @Bean
    @ConditionalOnMissingBean
    public RedisLockUtil redisLock() {
        return new RedisLockUtil();
    }

    @Bean
    @ConditionalOnMissingBean
    public RedissonLockUtil redissonLock() {
        return new RedissonLockUtil();
    }


    /**
     * 配置 RedisTemplate 以定义键值对的序列化方式
     * 此方法在 Spring 的 IoC 容器中定义了一个 Bean，类型为 RedisTemplate，用于操作 Redis 数据库
     * 通过自定义序列化方式，优化数据在 Redis 中的存储格式
     *
     * @param factory Redis 连接工厂，用于创建和管理 Redis 连接
     * @return 返回一个配置好的 RedisTemplate 实例，用于进行 Redis 操作
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 创建 RedisTemplate 实例
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂
        template.setConnectionFactory(factory);

        // 使用 StringRedisSerializer 作为 key 的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 设置 key 和 hashKey 的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);

        // 使用 Jackson2JsonRedisSerializer 作为 value 的序列化方式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        // 创建 ObjectMapper 实例
        ObjectMapper objectMapper = new ObjectMapper();
        // 设置对象所有属性的可见性，确保所有属性都能被序列化和反序列化
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 启用默认类型检测，允许序列化和反序列化时识别具体的子类类型
        // objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // 使用 LaissezFaireSubTypeValidator 作为子类型验证器，配合默认类型检测
        objectMapper.activateDefaultTyping(new LaissezFaireSubTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        objectMapper.registerModule(javaTimeModule);
        // 设置 ObjectMapper 到序列化器
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 设置 value 和 hashValue 的序列化方式
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        // 初始化 RedisTemplate，确保所有必要属性都已设置
        template.afterPropertiesSet();
        // 返回配置好的 RedisTemplate 实例
        return template;
    }

//    @ConditionalOnMissingBean
//    @Bean(name = "redisTemplate")
//    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//        RedisTemplate<String, Object> template = new RedisTemplate<>();
//        template.setConnectionFactory(factory);
//        FastJson2JsonRedisSerializer<Object> jacksonSerializer = new FastJson2JsonRedisSerializer<>(Object.class);
//
//        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//        // key采用String的序列化方式
//        template.setKeySerializer(stringRedisSerializer);
//        // hash的key也采用String的序列化方式
//        template.setHashKeySerializer(stringRedisSerializer);
//
//        // value序列化方式采用fastJson
//        template.setValueSerializer(jacksonSerializer);
//        // hash的value序列化方式采用fastJson
//        template.setHashValueSerializer(jacksonSerializer);
//
//        template.afterPropertiesSet();
//        return template;
//    }

}
